﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Kaesoft.Hospedaje.Common;
using Kaesoft.Hospedaje.Entities;
using System.Collections.Generic;
using Kaesoft.Hospedaje.Proxy;
using Kaesoft.Hospedaje.Proxy.AdministracionReference;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Linq;

namespace Kaesoft.Hospedaje.Admin
{
    public class AdministracionUsuarioViewModel : ViewModelBase
    {
        #region Variables
        private List<Catalogo> _tiposConsulta;
        private ObservableCollection<Perfil> _Perfiles;
        private ObservableCollection<Usuario> _usuarios;
        private ObservableCollection<CatalogoSummary> _regiones;
        private RelayCommand _buscarCommand;
        private Catalogo _tipoConsulta;
        private bool _modoLectura = true;
        private string _criterio;
        private int _totalUsuarios;
        private bool _isVisible;
        private Perfil _perfilSeleccionado;

        public Perfil PerfilSeleccionado
        {   
            get { return _perfilSeleccionado; }
            set
            {
                if (_perfilSeleccionado != value)
                {
                    _perfilSeleccionado = value;
                    OnPropertyChanged("PerfilSeleccionado");
                }
            }
        }
        
        
        public bool IsVisible
        {
            get { return _isVisible; }
            set
            {
                if (_isVisible != value)
                {
                    _isVisible = value;
                    OnPropertyChanged("IsVisible");
                }
            }
        }
        
        #endregion

        #region Propiedades

        /// <summary>
        /// Comando para la búsqueda de usuarios
        /// </summary>
        public RelayCommand BuscarCommand { get { return (_buscarCommand = new RelayCommand(ConsultarUsuarios, ValidarCriterios)); } }

        /// <summary>
        /// Tipo de consulta para ejecutar la búsqueda de usuarios
        /// </summary>
        public Catalogo TipoConsulta
        {
            get { return _tipoConsulta; }
            set { _tipoConsulta = value; OnPropertyChanged("TipoConsulta"); OnPropertyChanged("BuscarCommand"); }
        }

        /// <summary>
        /// Regiones del sistema
        /// </summary>
        public ObservableCollection<CatalogoSummary> Regiones
        {
            get { return _regiones; }
            set { _regiones = value; OnPropertyChanged("Regiones"); }
        }

        /// <summary>
        /// Perfiles del sistema
        /// </summary>
        public ObservableCollection<Perfil> Perfiles
        {
            get { return _Perfiles; }
            set { _Perfiles = value; OnPropertyChanged("Perfiles"); }
        }

        /// <summary>
        /// Criterio de búsqueda de usuarios
        /// </summary>
        public string Criterio
        {
            get { return _criterio; }
            set { _criterio = value; OnPropertyChanged("Criterio"); OnPropertyChanged("BuscarCommand"); ValidarCriterio(); }
        }

        /// <summary>
        /// Indica si los controles están o no en modo de lectura
        /// </summary>
        public bool ModoLectura
        {
            get { return _modoLectura; }
            set { _modoLectura = value; OnPropertyChanged("ModoLectura"); }
        }

        /// <summary>
        /// Lista de usuarios que se muestran en la grilla
        /// </summary>
        public ObservableCollection<Usuario> Usuarios
        {
            get { return _usuarios; }
            set { _usuarios = value; OnPropertyChanged("Usuarios"); }
        }

        /// <summary>
        /// Lista de los posibles tipos de consulta
        /// </summary>
        public List<Catalogo> TiposConsulta
        {
            get { return _tiposConsulta; }
            set { _tiposConsulta = value; OnPropertyChanged("TiposConsulta"); }
        }

        /// <summary>
        /// Número total de registros para comisionar
        /// </summary>
        public int TotalUsuarios
        {
            get
            {
                return _totalUsuarios;
            }
            set
            {
                if (_totalUsuarios != value)
                {
                    _totalUsuarios = value;
                    OnPropertyChanged("TotalUsuarios");
                }
            }
        }
        #endregion

        #region Eventos
        #endregion

        #region Constructor
        public AdministracionUsuarioViewModel()
        {
            #region Implementación
            BarraTareasViewModel = new BarraTareasViewModel();
            MessageBoxWindow = new MessageWindowView();
            BarraTareasViewModel.IsVisibleNuevo = true;
            BarraTareasViewModel.IsVisibleGuardar = true;
            BarraTareasViewModel.IsVisibleEditar = true;
            BarraTareasViewModel.IsVisibleCancelar = true;
            BarraTareasViewModel.IsEnableNuevo = true;
            BarraTareasViewModel.IsEnableEditar = true;
            BarraTareasViewModel.IsEnableCancelar = true;
            ModoLectura = true;
            IsVisible = false;

            BarraTareasViewModel.BotonTareaClick += new EventHandler<EventArgs<string>>(BotonOperacionClick);

            if (!Design.IsInDesignModeStatic)
            {
                CargarCatalogo();
            }
            #endregion

        }
        #endregion

        #region Métodos Públicos
        #endregion

        #region Métodos Privados
        /// <summary>
        /// Carga los catálogos necesarios en la pantalla
        /// </summary>
        private void CargarCatalogo()
        {
            #region Implementación
            Procesando = true;

            List<Catalogo> tiposConsulta = new List<Catalogo>();
            tiposConsulta.Add(new Catalogo() { codigo = (int)TipoConsultaUsuario.Nombre, nombre = "Nombre" });
            tiposConsulta.Add(new Catalogo() { codigo = (int)TipoConsultaUsuario.Usuario, nombre = "Usuario" });
            tiposConsulta.Add(new Catalogo() { codigo = (int)TipoConsultaUsuario.Identificacion, nombre = "Identificación" });

            TiposConsulta = tiposConsulta;

            //Regiones = new ObservableCollection<CatalogoSummary>(Caching.Instancia.Catalogos(TipoCatalogo.REGIONES));

            ProxyAdministracion.ObtenerPerfilesAsync(ev => ObtenerPerfilesCompleted(null, ev));
            #endregion
        }

        /// <summary>
        /// Método resultado de la consulta de perfiles del sistema
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ObtenerPerfilesCompleted(object sender, ObtenerPerfilesCompletedEventArgs e)
        {
            #region Implementación
            if (e.Error == null)
            {
                Perfiles = new ObservableCollection<Perfil>(e.Result);
            }

            Procesando = false;
            #endregion
        }

        /// <summary>
        /// Método que permite ejecutar las acciones de la barra de tareas
        /// </summary>
        /// <param name="sender">Barra de tareas</param>
        /// <param name="e">Acción ejecutada</param>
        private void BotonOperacionClick(object sender, EventArgs<string> e)
        {
            #region Implementación
            switch (e.Data)
            {
                case "Nuevo":
                    Usuario usuario = new Usuario();
                    usuario.Validator.ValidateAll();
                    Usuarios = new ObservableCollection<Usuario>();
                    Usuarios.Add(usuario);
                    ((INotifyPropertyChanged)Usuarios).PropertyChanged += new PropertyChangedEventHandler(AdministracionUsuarioViewModel_PropertyChanged);
                    BarraTareasViewModel.IsEnableGuardar = true;
                    BarraTareasViewModel.IsEnableEditar = false;
                    BarraTareasViewModel.IsEnableNuevo = false;
                    ModoLectura = false;
                    break;
                case "Editar":
                    BarraTareasViewModel.IsEnableGuardar = true;
                    BarraTareasViewModel.IsEnableEditar = false;
                    BarraTareasViewModel.IsEnableNuevo = false;
                    ModoLectura = false;
                    IsVisible = true;
                    break;
                case "Guardar":
                    if (Usuarios != null)
                    {
                        GuardarUsuario();
                    }

                    break;
                case "Cancelar":
                    if (IsDirty)
                    {
                        EjecutaMensaje("Está seguro de cancelar? Perderá los cambios en los elementos no guardados.", MessageBoxButtons.OkCancel, MessageBoxIcon.Question);
                        break;
                    }
                    else
                    {
                        Usuarios = new ObservableCollection<Usuario>();
                        BarraTareasViewModel.IsEnableGuardar = false;
                        BarraTareasViewModel.IsEnableEditar = true;
                        BarraTareasViewModel.IsEnableNuevo = true;
                        ModoLectura = true;
                        IsVisible = false;
                        IsDirty = false;
                    }
                    break;
                default:
                    break;
            }
            #endregion
        }

        public void EjecutaMensaje(string mensaje, MessageBoxButtons botones, MessageBoxIcon icono)
        {
            MessageWindowViewModel msgvm = new MessageWindowViewModel(mensaje, botones, icono);
            MessageBoxWindow.DataContext = msgvm;
            msgvm.Closing += (msgsender, ev) =>
            {
                MessageBoxWindow.Close();
                if (ev.Data == MessageBoxResult.OK)
                {
                    Usuarios = new ObservableCollection<Usuario>();
                    BarraTareasViewModel.IsEnableGuardar = false;
                    BarraTareasViewModel.IsEnableEditar = true;
                    BarraTareasViewModel.IsEnableNuevo = true;
                    ModoLectura = true;
                    IsDirty = false;
                }
                else
                {
                    return;
                }
            };
            MessageBoxWindow.ShowDialog();
        }

        /// <summary>
        /// Valida datos de consulta para habilitar el botón de consulta
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        private bool ValidarCriterios(object sender)
        {
            return !(TipoConsulta == null);
        }

        /// <summary>
        /// Método que se invoca cuando los valores de una entidad 
        /// cambian para indicar que existe una modificación en la pantalla
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AdministracionUsuarioViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            IsDirty = true;
        }

        /// <summary>
        /// Guarda los datos de los usuarios nuevos o modificados
        /// </summary>
        private void GuardarUsuario()
        {
            #region Implementación
            List<ErrorMessage> errores = new List<ErrorMessage>();
            ErrorList.Clear();
            var listaUsuarios = ObtenerUsuariosModificados();
            listaUsuarios.ForEach(usuarioInd =>
            {
                errores = new List<ErrorMessage>(usuarioInd.Validator.ValidateAll());

                //if(usuarioInd.idUsuario == Caching.Instancia.UsuarioSistema.idUsuario)
                //    errores.Add(new ErrorMessage("No se puede modificar la informacion de este usuario ya que se encuentra con una sesion activa.", ErrorType.InvalidFormat));
                
                ProxyAdministracion.ValidaUsuarioAsync(usuarioInd, evnt =>
                {
                    if (evnt.Error != null)
                        return;
                    var verificador = (Dictionary<string, int>)evnt.Result;
                    if (verificador["UserName"] > 0)
                        errores.Add(new ErrorMessage("El usuario que desea guardar ya existe", ErrorType.InvalidFormat));
                    if (verificador["UserKeys"] > 0)
                        errores.Add(new ErrorMessage("Ya existe un usuario con los numero de identificacion y convenio ingresados", ErrorType.InvalidFormat));

                    if (listaUsuarios.Count > 0 && !(listaUsuarios.Any(usuario => usuario.HasErrors)) && !(errores.Count > 0))
                    {
                        Procesando = true;
                        ProxyAdministracion.GrabarUsuariosAsync(listaUsuarios, ev => GrabarUsuariosCompleted(null, ev));
                    }
                    else
                    {
                        errores.ForEach(a => ErrorList.Add(a));
                        return;
                    }
                });
            });


            #endregion
        }

        /// <summary>
        /// Método resultado del proceso de grabación de usuarios
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">Resultado de la consulta</param>
        private void GrabarUsuariosCompleted(object sender, AsyncCompletedEventArgs e)
        {
            #region Implementación
            if (e.Error == null)
            {
                ModoLectura = true;
                IsDirty = false;
                BarraTareasViewModel.IsEnableGuardar = false;
                BarraTareasViewModel.IsEnableEditar = true;
                BarraTareasViewModel.IsEnableNuevo = true;
                IsVisible = false;
            }

            this.Procesando = false;
            #endregion
        }

        /// <summary>
        /// Método para consultar los usuarios por criterios
        /// </summary>
        /// <param name="parameter"></param>
        private void ConsultarUsuarios(object parameter)
        {
            #region Implementación
            ValidarCriterio();
            if (!ErrorList.Any())
            {
                if (IsDirty)
                {
                    MessageWindowViewModel msgvm = new MessageWindowViewModel("Está seguro de realizar la busqueda? Perderá los cambios en los elementos no guardados.", MessageBoxButtons.OkCancel, MessageBoxIcon.Question);
                    MessageBoxWindow.DataContext = msgvm;
                    msgvm.Closing += (msgsender, ev) =>
                    {
                        MessageBoxWindow.Close();
                        if (ev.Data == MessageBoxResult.OK)
                        {
                            RealizarConsulta();
                        }
                        else
                        {
                            return;
                        }
                    };
                    MessageBoxWindow.ShowDialog();
                    return;
                }

                RealizarConsulta();
            }
            #endregion
        }

        /// <summary>
        /// Ejecuta la consulta de usuarios
        /// </summary>
        private void RealizarConsulta()
        {
            BarraTareasViewModel.IsEnableGuardar = false;
            BarraTareasViewModel.IsEnableEditar = true;
            BarraTareasViewModel.IsEnableNuevo = true;
            ModoLectura = true;
            IsDirty = false;
            Procesando = true;

            if (TotalUsuarios > 0)
                OnResetPager("PagerUsuarios");

            ProxyAdministracion.ObtenerUsuariosPorCriteriosAsync(TipoConsulta.codigo, Criterio ?? string.Empty, 0, ev => ObtenerUsuariosPorCriteriosCompleted(null, ev));

        }

        /// <summary>
        /// Método resultado de la consulta de usuarios por criterios
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">Resultado de la consulta</param>
        private void ObtenerUsuariosPorCriteriosCompleted(object sender, ObtenerUsuariosPorCriteriosCompletedEventArgs e)
        {
            #region Implementación
            if (e.Error == null)
            {
                Usuarios = new ObservableCollection<Usuario>(e.Result.Entidades);
                TotalUsuarios = e.Result.TotalRegistros;
                //var usuarioActual = Caching.Instancia.UsuarioSistema;
                var seleccionado = Usuarios.Where(a => a.idUsuario == Caching.Instancia.UsuarioSistema.idUsuario).FirstOrDefault();
                if (seleccionado != null)
                    seleccionado.EsUsuarioActual = true;

                foreach (var usuario in Usuarios)
                {
                    ((INotifyPropertyChanged)usuario).PropertyChanged += new PropertyChangedEventHandler(AdministracionUsuarioViewModel_PropertyChanged);
                }
            }

            this.Procesando = false;
            #endregion
        }

        /// <summary>
        /// Listado de lo usuarios nuevos o modificados
        /// </summary>
        /// <returns>Lista de usuarios</returns>
        private List<Usuario> ObtenerUsuariosModificados()
        {
            #region Implementación
            var lista = Usuarios.Where(u => u.ChangeTracker.State != ObjectState.Unchanged).ToList();
            return lista;
            #endregion
        }

        /// <summary>
        /// Método para validar los datos de criterios de consulta por el tipo
        /// </summary>
        private void ValidarCriterio()
        {
            #region Implementación
            ErrorList.Clear();
            switch (TipoConsulta.codigo)
            {
                case (int)TipoConsultaUsuario.Codigo:
                    if ((Criterio ?? string.Empty) == string.Empty || System.Text.RegularExpressions.Regex.IsMatch(Criterio ?? string.Empty, "[^0-9]"))
                    {
                        ErrorList.Add(new ErrorMessage("Criterio es un campo numérico", ErrorType.InvalidFormat, "Criterio"));
                    }
                    break;
                case (int)TipoConsultaUsuario.Nombre:
                    if (System.Text.RegularExpressions.Regex.IsMatch(Criterio ?? string.Empty, "[^a-zA-Z]"))
                    {
                        ErrorList.Add(new ErrorMessage("Criterio es un campo alfabético", ErrorType.InvalidFormat, "Criterio"));
                    }
                    break;
                case (int)TipoConsultaUsuario.Usuario:
                    break;
                case (int)TipoConsultaUsuario.Identificacion:
                    break;
                default:
                    break;
            }
            #endregion
        }

        internal void CargarUsuarios(int p)
        {
            if (TipoConsulta == null) return;

            Procesando = true;
            ProxyAdministracion.ObtenerUsuariosPorCriteriosAsync(TipoConsulta.codigo, Criterio ?? string.Empty, p, ev => ObtenerUsuariosPorCriteriosCompleted(null, ev));
        }

        #endregion
    }
}
